package com.ruoyi.rabbitmq.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.amqp.rabbit.core.RabbitAdmin;

import javax.annotation.PostConstruct;

/**
 * RabbitMQ配置
 * 
 * @author ruoyi
 */
@Configuration
@ConditionalOnProperty(name = "spring.rabbitmq.enabled", havingValue = "true", matchIfMissing = true)
public class RabbitMQConfig
{
    @Value("${spring.rabbitmq.host:localhost}")
    private String host;

    @Value("${spring.rabbitmq.port:5672}")
    private int port;

    @Value("${spring.rabbitmq.username:guest}")
    private String username;

    @Value("${spring.rabbitmq.password:guest}")
    private String password;

    @Value("${spring.rabbitmq.virtual-host:/}")
    private String virtualHost;

    @Value("${spring.rabbitmq.connection-timeout:5000}")
    private int connectionTimeout;

    @Value("${spring.rabbitmq.heartbeat:60}")
    private int heartbeat;

    @Value("${spring.rabbitmq.automatic-recovery-enabled:true}")
    private boolean automaticRecoveryEnabled;

    @Value("${spring.rabbitmq.network-recovery-interval:5000}")
    private int networkRecoveryInterval;

    @Value("${spring.rabbitmq.publisher-confirms:true}")
    private boolean publisherConfirms;

    @Value("${spring.rabbitmq.publisher-returns:true}")
    private boolean publisherReturns;

    @Value("${spring.rabbitmq.concurrent-consumers:1}")
    private int concurrentConsumers;

    @Value("${spring.rabbitmq.max-concurrent-consumers:10}")
    private int maxConcurrentConsumers;

    @Value("${spring.rabbitmq.prefetch-count:1}")
    private int prefetchCount;

    // 交换机名称
    public static final String DIRECT_EXCHANGE = "ruoyi.direct.exchange";
    public static final String TOPIC_EXCHANGE = "ruoyi.topic.exchange";
    public static final String FANOUT_EXCHANGE = "ruoyi.fanout.exchange";
    public static final String DEAD_LETTER_EXCHANGE = "ruoyi.dead.letter.exchange";

    // 队列名称
    public static final String DIRECT_QUEUE = "ruoyi.direct.queue";
    public static final String TOPIC_QUEUE_1 = "ruoyi.topic.queue.1";
    public static final String TOPIC_QUEUE_2 = "ruoyi.topic.queue.2";
    public static final String FANOUT_QUEUE_1 = "ruoyi.fanout.queue.1";
    public static final String FANOUT_QUEUE_2 = "ruoyi.fanout.queue.2";
    public static final String DEAD_LETTER_QUEUE = "ruoyi.dead.letter.queue";
    public static final String RETRY_QUEUE = "ruoyi.retry.queue";

    // 路由键
    public static final String DIRECT_ROUTING_KEY = "ruoyi.direct.routing.key";
    public static final String TOPIC_ROUTING_KEY_1 = "ruoyi.topic.*";
    public static final String TOPIC_ROUTING_KEY_2 = "ruoyi.topic.#";
    public static final String DEAD_LETTER_ROUTING_KEY = "ruoyi.dead.letter.routing.key";

    @PostConstruct
    public void init() {
        System.out.println("=== RabbitMQ配置初始化 ===");
        System.out.println("host: " + host);
        System.out.println("port: " + port);
        System.out.println("username: " + username);
        System.out.println("password: " + password);
        System.out.println("virtualHost: " + virtualHost);
        System.out.println("connectionTimeout: " + connectionTimeout);
        System.out.println("heartbeat: " + heartbeat);
        System.out.println("automaticRecoveryEnabled: " + automaticRecoveryEnabled);
        System.out.println("networkRecoveryInterval: " + networkRecoveryInterval);
        System.out.println("publisherConfirms: " + publisherConfirms);
        System.out.println("publisherReturns: " + publisherReturns);
        System.out.println("concurrentConsumers: " + concurrentConsumers);
        System.out.println("maxConcurrentConsumers: " + maxConcurrentConsumers);
        System.out.println("prefetchCount: " + prefetchCount);
        System.out.println("===========================");
    }

    /**
     * 连接工厂配置
     */
    @Bean
    public ConnectionFactory connectionFactory()
    {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setHost(host);
        connectionFactory.setPort(port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        
        // 输出配置信息用于调试
        System.out.println("=== RabbitMQ连接工厂配置 ===");
        System.out.println("host: " + host);
        System.out.println("port: " + port);
        System.out.println("username: " + username);
        System.out.println("password: " + password);
        System.out.println("virtualHost: " + virtualHost);
        System.out.println("=============================");
        
        // 开启发送确认
        connectionFactory.setPublisherConfirms(publisherConfirms);
        // 开启发送失败退回
        connectionFactory.setPublisherReturns(publisherReturns);
        
        // 设置连接超时时间
        connectionFactory.setConnectionTimeout(connectionTimeout);
        
        // 设置心跳间隔
        connectionFactory.setRequestedHeartBeat(heartbeat);
        
        // 设置自动恢复连接
        connectionFactory.getRabbitConnectionFactory().setAutomaticRecoveryEnabled(automaticRecoveryEnabled);
        
        // 设置网络恢复间隔
        connectionFactory.getRabbitConnectionFactory().setNetworkRecoveryInterval(networkRecoveryInterval);
        
        return connectionFactory;
    }

    /**
     * 消息转换器
     */
    @Bean
    public MessageConverter jsonMessageConverter()
    {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * RabbitTemplate配置
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory)
    {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(jsonMessageConverter());
        
        // 消息发送确认回调
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack)
            {
                System.out.println("消息发送成功");
            }
            else
            {
                System.out.println("消息发送失败：" + cause);
            }
        });
        
        // 消息发送失败退回回调
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            System.out.println("消息发送失败退回：" + message);
        });
        
        return rabbitTemplate;
    }

    /**
     * 消费者监听器工厂配置
     */
    @Bean
    public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory)
    {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(jsonMessageConverter());
        
        // 手动确认
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        // 消费者数量
        factory.setConcurrentConsumers(concurrentConsumers);
        factory.setMaxConcurrentConsumers(maxConcurrentConsumers);
        // 预取数量
        factory.setPrefetchCount(prefetchCount);
        
        // 设置连接失败时的处理
        factory.setMissingQueuesFatal(false);
        factory.setDefaultRequeueRejected(false);
        
        return factory;
    }

    /**
     * RabbitAdmin配置
     */
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory)
    {
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    /**
     * 直连交换机
     */
    @Bean
    public DirectExchange directExchange()
    {
        return new DirectExchange(DIRECT_EXCHANGE, true, false);
    }

    /**
     * 主题交换机
     */
    @Bean
    public TopicExchange topicExchange()
    {
        return new TopicExchange(TOPIC_EXCHANGE, true, false);
    }

    /**
     * 扇形交换机
     */
    @Bean
    public FanoutExchange fanoutExchange()
    {
        return new FanoutExchange(FANOUT_EXCHANGE, true, false);
    }

    /**
     * 死信交换机
     */
    @Bean
    public DirectExchange deadLetterExchange()
    {
        return new DirectExchange(DEAD_LETTER_EXCHANGE, true, false);
    }

    /**
     * 死信队列
     */
    @Bean
    public Queue deadLetterQueue()
    {
        return new Queue(DEAD_LETTER_QUEUE, true);
    }

    /**
     * 重试队列
     */
    @Bean
    public Queue retryQueue()
    {
        return QueueBuilder.durable(RETRY_QUEUE)
                .withArgument("x-dead-letter-exchange", DIRECT_EXCHANGE)
                .withArgument("x-dead-letter-routing-key", DIRECT_ROUTING_KEY)
                .withArgument("x-message-ttl", 10000) // 10秒后重试
                .build();
    }

    /**
     * 直连队列
     */
    @Bean
    public Queue directQueue()
    {
        return QueueBuilder.durable(DIRECT_QUEUE)
                .withArgument("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE)
                .withArgument("x-dead-letter-routing-key", DEAD_LETTER_ROUTING_KEY)
                .build();
    }

    /**
     * 主题队列1
     */
    @Bean
    public Queue topicQueue1()
    {
        return QueueBuilder.durable(TOPIC_QUEUE_1)
                .withArgument("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE)
                .withArgument("x-dead-letter-routing-key", DEAD_LETTER_ROUTING_KEY)
                .build();
    }

    /**
     * 主题队列2
     */
    @Bean
    public Queue topicQueue2()
    {
        return QueueBuilder.durable(TOPIC_QUEUE_2)
                .withArgument("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE)
                .withArgument("x-dead-letter-routing-key", DEAD_LETTER_ROUTING_KEY)
                .build();
    }

    /**
     * 扇形队列1
     */
    @Bean
    public Queue fanoutQueue1()
    {
        return QueueBuilder.durable(FANOUT_QUEUE_1)
                .withArgument("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE)
                .withArgument("x-dead-letter-routing-key", DEAD_LETTER_ROUTING_KEY)
                .build();
    }

    /**
     * 扇形队列2
     */
    @Bean
    public Queue fanoutQueue2()
    {
        return QueueBuilder.durable(FANOUT_QUEUE_2)
                .withArgument("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE)
                .withArgument("x-dead-letter-routing-key", DEAD_LETTER_ROUTING_KEY)
                .build();
    }

    /**
     * 绑定直连队列到直连交换机
     */
    @Bean
    public Binding directBinding()
    {
        return BindingBuilder.bind(directQueue()).to(directExchange()).with(DIRECT_ROUTING_KEY);
    }

    /**
     * 绑定主题队列1到主题交换机
     */
    @Bean
    public Binding topicBinding1()
    {
        return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with(TOPIC_ROUTING_KEY_1);
    }

    /**
     * 绑定主题队列2到主题交换机
     */
    @Bean
    public Binding topicBinding2()
    {
        return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with(TOPIC_ROUTING_KEY_2);
    }

    /**
     * 绑定扇形队列1到扇形交换机
     */
    @Bean
    public Binding fanoutBinding1()
    {
        return BindingBuilder.bind(fanoutQueue1()).to(fanoutExchange());
    }

    /**
     * 绑定扇形队列2到扇形交换机
     */
    @Bean
    public Binding fanoutBinding2()
    {
        return BindingBuilder.bind(fanoutQueue2()).to(fanoutExchange());
    }

    /**
     * 绑定死信队列到死信交换机
     */
    @Bean
    public Binding deadLetterBinding()
    {
        return BindingBuilder.bind(deadLetterQueue()).to(deadLetterExchange()).with(DEAD_LETTER_ROUTING_KEY);
    }
} 